# FILEPATH: PDFeXpress/src/app/add_toc.py
import tkinter as tk
from tkinter import ttk
from tkinter import filedialog
from pathlib import Path
import fitz
import csv
import time
import chardet
from tkinter.filedialog import askdirectory
from tkinter.messagebox import showinfo
import tkinterdnd2
from threading import Thread
# 修改后的引用
from utility import drop_pdf_file_to_entry  # 支持拖放PDF文件
from widget import Process, FrameTitle, OutputFolder, InputFile  # 文件选择、输出目录和进度条功能

class AddTOC(ttk.Frame):
    def __init__(self, master=None, **kw):
        super().__init__(master, **kw)
        self.FrameTitle = FrameTitle(master=self, frame_title=_('Add Bookmark'))
        self.FrameTitle.pack(fill='x', padx=4, pady=4)

        self.InputFile = InputFile(master=self)
        self.InputFile.input_file.trace_add('write', self.trace_input_file)

        # 存储目录数据
        self.toc_data = []
        # 特有功能：加载CSV目录文件，修改为和InputFile一样的功能
        self.ButtonLoadCSV = ttk.Button(master=self, text="打开CSV文件", command=self.load_csv_file)
        self.ButtonLoadCSV.pack(pady=10, fill=tk.X, padx=5)

        # 添加 Entry 控件用于显示加载的 CSV 文件路径
        self.csv_path_entry = ttk.Entry(master=self, state='readonly')
        self.csv_path_entry.pack(pady=5, fill=tk.X, padx=5)

        # 特有功能：页码偏移量
        self.offset_frame = ttk.Frame(master=self)
        self.offset_frame.pack(pady=10, fill=tk.X, padx=5)

        self.offset_label = ttk.Label(self.offset_frame, text="页码偏移量：")
        self.offset_label.pack(side=tk.LEFT, padx=5)

        self.offset_entry = ttk.Entry(self.offset_frame, width=8)
        self.offset_entry.insert(0, "0")  # 默认偏移量0
        self.offset_entry.pack(side=tk.LEFT)

        self.offset_tip = ttk.Label(self.offset_frame, text="(正数延后，负数提前)")
        self.offset_tip.pack(side=tk.LEFT, padx=5)

        self.OutputFolder = OutputFolder(master=self)
        self.OutputFolder.configure(text=_('PDF Output Folder'))
        self.OutputFolder.ButtonOutputFolder.configure(command=self.set_output_folder)

        self.Process = Process(master=self)
        self.Process.configure(text=_('Add Bookmark'))
        self.Process.ButtonProcess.configure(text=_('Add'), command=self.add_toc_to_pdf)

        # 添加一个 Label 控件用于显示进度百分比
        self.progress_label = ttk.Label(self, text="")
        self.progress_label.pack(pady=5)

        self.drop_target_register(tkinterdnd2.DND_FILES)
        self.dnd_bind('<<Drop>>', self.drop_files)

    def drop_files(self, event):
        files = event.data.split()
        for file in files:
            if file.lower().endswith('.pdf'):
                drop_pdf_file_to_entry(self.InputFile.input_file, event)
            elif file.lower().endswith('.csv'):
                self.csv_path_entry.config(state='normal')
                self.csv_path_entry.delete(0, tk.END)
                self.csv_path_entry.insert(0, file)
                self.csv_path_entry.config(state='readonly')
                self.load_toc_csv()

    def trace_input_file(self, *args):
        input_file = self.InputFile.input_file.get()
        if input_file:
            self.OutputFolder.output_folder.set(Path(input_file).parent)

    def set_output_folder(self):
        initial_dir = None
        current_folder = self.OutputFolder.output_folder.get()
        if current_folder:
            initial_dir = Path(current_folder)
        else:
            input_file = self.InputFile.input_file.get()
            if input_file:
                initial_dir = Path(input_file).parent
        folder = askdirectory(
            title=_('Select PDF Output Folder'),
            initialdir=initial_dir
        )
        if folder:
            self.OutputFolder.output_folder.set(Path(folder))

    def load_csv_file(self):
        """打开CSV文件"""
        file_path = filedialog.askopenfilename(filetypes=[("CSV Files", "*.csv")])
        if file_path:
            self.csv_path_entry.config(state='normal')
            self.csv_path_entry.delete(0, tk.END)
            self.csv_path_entry.insert(0, file_path)
            self.csv_path_entry.config(state='readonly')
            self.load_toc_csv()

    def load_toc_csv(self):
        """特有功能：加载CSV目录文件"""
        file_path = self.csv_path_entry.get()
        if not file_path:
            return

        self.toc_data.clear()

        try:
            # 自动检测编码和分隔符
            with open(file_path, 'rb') as f:
                raw_data = f.read()
            encoding = chardet.detect(raw_data)['encoding'] or 'utf-8'
            sniff_data = raw_data.decode(encoding, errors='ignore')[:1024]
            dialect = csv.Sniffer().sniff(sniff_data, delimiters=['\t', ',', ';'])

            # 读取数据
            with open(file_path, 'r', encoding=encoding, newline='') as f:
                reader = csv.reader(f, dialect=dialect)
                for row_num, row in enumerate(reader, 1):
                    # 清理数据
                    cleaned_row = [
                        cell.strip(' |\t\u3000\xa0')  # 去除全角空格、不间断空格等
                        for cell in row
                        if cell.strip()
                    ]

                    # 跳过空行和标题行
                    if len(cleaned_row) == 0:
                        continue

                    # 数据校验
                    try:
                        if len(cleaned_row) == 2:
                            # 当只有两列时，默认层级为 1
                            level = 1
                            title = cleaned_row[0]
                            page = int(cleaned_row[1])
                        elif len(cleaned_row) == 3:
                            level = int(cleaned_row[0])
                            title = cleaned_row[1]
                            page = int(cleaned_row[2])
                        else:
                            showinfo(title="错误",
                                     message=f"第{row_num}行数据列数错误，应为 2 列或 3 列\n"
                                             f"当前内容：{row}")
                            self.toc_data.clear()
                            return
                        self.toc_data.append((level, title, page))
                    except (ValueError, IndexError):
                        showinfo(title="错误",
                                 message=f"第{row_num}行数据格式错误\n"
                                         f"示例正确格式：1[TAB]第一章[TAB]1 或 第一章[TAB]1\n"
                                         f"当前内容：{row}")
                        self.toc_data.clear()
                        return
            # 成功加载后弹出提示框
            # showinfo(title="成功", message="成功加载 CSV 目录文件")

        except Exception as e:
            showinfo(title="错误", message=f"文件解析失败：{str(e)}")
            self.toc_data.clear()

    def add_toc_to_pdf(self):
        """整合功能：添加目录到PDF"""
        input_file = self.InputFile.input_file.get()  # 获取输入文件路径
        output_dir = self.OutputFolder.output_folder.get()  # 获取输出目录
        file_path = self.csv_path_entry.get()

        if not input_file or not file_path:
            showinfo(title="错误", message="请先选择输入PDF、CSV文件")
            return

         # 获取页码偏移量
        try:
            page_offset = int(self.offset_entry.get())
        except ValueError:
            showinfo(title="错误", message="偏移量必须为整数")
            return

        Thread(target=self._process_pdf_in_thread, args=(input_file, output_dir, page_offset)).start()

    def _process_pdf_in_thread(self, input_file, output_dir, page_offset):

        #  # 获取页码偏移量
        # try:
        #     page_offset = int(self.offset_entry.get())
        # except ValueError:
        #     showinfo(title="错误", message="偏移量必须为整数")
        #     return
         # 设置进度条总量为 adjusted_toc 的长度
        total_steps = len(self.toc_data)+1
        self.Process.ProgressBar.grab_set()
        self.Process.process.set(0)
        self.Process.ProgressBar.configure(maximum=total_steps)
        self.update_progress_label(0)
        try:
            # 步骤 1: 打开 PDF 文件
            doc = fitz.Document(input_file)
            total_pages = doc.page_count
            # self.update_progress(10, total_steps)

            # 步骤 2: 应用页码偏移并验证
            valid_adjusted_toc = []
            for i, (level, title, page) in enumerate(self.toc_data, start=1):
                adjusted_page = page + page_offset
                if adjusted_page < 1 or adjusted_page > total_pages:
                    showinfo(title="错误",
                            message=f"页码{page}偏移后({adjusted_page})无效\n"
                                    f"有效范围：1-{total_pages}")
                    self.master.after(100, lambda: self.Process.process.set(0))
                    self.master.after(100, lambda: self.progress_label.config(text=""))
                    return
                valid_adjusted_toc.append((level, title, adjusted_page))
                self.update_progress(i, total_steps)
           
                # 步骤 3: 设置目录
            doc.set_toc(valid_adjusted_toc)     

            # 步骤 4: 保存 PDF 文件
            output_file = f"{output_dir}/output_with_toc.pdf"
            # doc.save(output_file, garbage=4, deflate=True)
            self.Process.process.set(total_steps - 1)
            self.update_progress_label(((total_steps - 1) / total_steps) * 100)
            # self.master.after(100, lambda: self.progress_label.config(text="正在保存文件，请稍候..."))
            doc.save(output_file, garbage=4, deflate=True)
                                   
            self.update_progress_label(100)
            self.update_progress(total_steps, total_steps)
            showinfo(title="完成", message=f"目录添加成功（已应用偏移{page_offset}页）")
            
            self.Process.ProgressBar.grab_release()
            self.Process.process.set(0)
            self.progress_label.config(text="")
        except Exception as e:
            showinfo(title="错误", message=f"PDF处理失败: {str(e)}")
            self.Process.process.set(0)
            self.progress_label.config(text="")
        finally:
            self.Process.ProgressBar.grab_release()
            

    def update_progress(self, step, total_steps):
        self.Process.process.set(step)
        self.Process.ProgressBar.update()
        percentage = (step / total_steps) * 100
        self.update_progress_label(percentage)

    def update_progress_label(self, percentage):
        if percentage >= 100:
            self.progress_label.config(text="100%，任务完成！")
        else:
            self.progress_label.config(text=f"{percentage:.0f}%")


# ------------------ 主程序入口 ------------------
if __name__ == "__main__":
    root = tkinterdnd2.Tk()
    root.title("PDF目录添加工具")
    app = AddTOC(root)
    app.pack(expand=True, fill='both', padx=4, pady=4)
    root.mainloop()